home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #1 / Ham Radio 2000.iso / ham2000 / tcp_ip / tnos / tnos100s / trace.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-11-27  |  12.9 KB  |  564 lines

  1. /* Packet tracing - top level and generic routines, including hex/ascii
  2.  * Copyright 1991 Phil Karn, KA9Q
  3.  *
  4.  * Mods by G1EMM
  5.  *
  6.  * Tracing to session taken from WNOS3, by Johan. K. Reinalda, WG7J
  7.  */
  8. #include <stdio.h>
  9. #include <ctype.h>
  10. #include <time.h>
  11. #include "global.h"
  12. #include "config.h"
  13. #ifdef ANSIPROTO
  14. #include <stdarg.h>
  15. #endif
  16. #include "mbuf.h"
  17. #include "iface.h"
  18. #include "pktdrvr.h"
  19. #include "commands.h"
  20. #include "session.h"
  21. #include "trace.h"
  22.  
  23. #ifdef TRACE
  24. static void ascii_dump __ARGS((FILE *fp,struct mbuf **bpp));
  25. static void ctohex __ARGS((char *buf,int16 c));
  26. static void fmtline __ARGS((FILE *fp,int16 addr,char *buf,int16 len));
  27. static void hex_dump __ARGS((FILE *fp,struct mbuf **bpp));
  28. static void showtrace __ARGS((struct iface *ifp));
  29. static void plain_dump __ARGS((FILE *fp,register struct mbuf **bpp));
  30. extern struct session *Current;
  31. extern struct session *Command;
  32. #ifdef MULTITASK
  33. extern int Nokeys;
  34. #endif
  35.  
  36. #ifdef TNOS_68K
  37. #define fprintf traceprintf
  38. #endif
  39.  
  40. extern int Tracesession;
  41. extern struct session *Trace;
  42.  
  43. #ifdef MONITOR
  44. int Trace_compact_header = 0;
  45. static char *kissname __ARGS((struct iface *ifp,struct mbuf *bp,int type));
  46.  
  47. #include "slip.h"
  48.  
  49. static char *
  50. kissname(ifp, bp, type)
  51. struct iface *ifp;
  52. struct mbuf *bp;
  53. int type;
  54. {
  55.     int port;
  56.  
  57.     if (ifp->type != CL_AX25 || type != CL_KISS)
  58.         return ifp->name;
  59.     port = (bp->data[0] & 0xF0) >> 4;
  60.     if (Slip[ifp->xdev].kiss[port] == NULLIF)
  61.         return ifp->name;
  62.     return Slip[ifp->xdev].kiss[port]->name;
  63. }
  64.  
  65. #endif
  66.  
  67. int
  68. dostrace(argc,argv,p)
  69. int argc;
  70. char *argv[];
  71. void *p;
  72. {
  73.     if(Trace == NULLSESSION)    {
  74.     if (argc > 1)
  75.             tputs ("Session tracing not available!\x07\n");
  76.         argc = 0; /* No session setup, so don't allow turning it on ! */
  77.     }
  78.     return setbool(&Tracesession,"Trace to session",argc,argv);
  79. }
  80.  
  81. /* Redefined here so that programs calling dump in the library won't pull
  82.  * in the rest of the package
  83.  */
  84.  
  85. static char nospace[] = "No space!!\n";
  86.  
  87. struct tracecmd Tracecmd[] = {
  88.     "input",    IF_TRACE_IN,    IF_TRACE_IN,
  89.     "-input",    0,        IF_TRACE_IN,
  90.     "output",    IF_TRACE_OUT,    IF_TRACE_OUT,
  91.     "-output",    0,        IF_TRACE_OUT,
  92.     "broadcast",    0,        IF_TRACE_NOBC,
  93.     "-broadcast",    IF_TRACE_NOBC,    IF_TRACE_NOBC,
  94.     "raw",        IF_TRACE_RAW,    IF_TRACE_RAW,
  95.     "-raw",        0,        IF_TRACE_RAW,
  96.     "ascii",    IF_TRACE_ASCII,    IF_TRACE_ASCII|IF_TRACE_HEX,
  97.     "-ascii",    0,        IF_TRACE_ASCII|IF_TRACE_HEX,
  98.     "hex",        IF_TRACE_HEX,    IF_TRACE_ASCII|IF_TRACE_HEX,
  99.     "-hex",        IF_TRACE_ASCII,    IF_TRACE_ASCII|IF_TRACE_HEX,
  100. #ifdef MONITOR
  101. /* borrow a meaningless combination for the new trace type */
  102. #define IF_TRACE_PLAIN (IF_TRACE_ASCII|IF_TRACE_HEX)
  103.   "monitor",  IF_TRACE_PLAIN, IF_TRACE_ASCII|IF_TRACE_HEX,
  104.   "-monitor", IF_TRACE_ASCII, IF_TRACE_ASCII|IF_TRACE_HEX,
  105. #endif
  106.     "off",        0,        0xffff,
  107.     NULLCHAR,    0,        0
  108. };
  109.  
  110. void
  111. dump(ifp,direction,type,bp)
  112. register struct iface *ifp;
  113. int direction;
  114. unsigned type;
  115. struct mbuf *bp;
  116. {
  117.     struct mbuf *tbp;
  118.     void (*func) __ARGS((FILE *,struct mbuf **,int));
  119.     int16 size;
  120.     time_t timer;
  121.     char *cp;
  122.  
  123.     if(ifp == NULL || (ifp->trace & direction) == 0)
  124.         return; /* Nothing to trace */
  125.  
  126.     if(Tracesession) {
  127.         /* Disable trace if this is not Trace-sessions,
  128.          * or when shelled out, and not tracing to file */
  129. #ifdef MULTITASK
  130.         if((Current != Trace || Nokeys) && (ifp->trfp == stdout))
  131. #else
  132.         if((Current != Trace) && (ifp->trfp == stdout))
  133. #endif /* MULTITASK */
  134.             return; /* Nothing to trace */
  135.     } else {
  136.         /* Disable trace on non-command sessions or when shelled out */
  137. #ifdef MULTITASK
  138.         if((Current != Command || Nokeys) && (ifp->trfp == stdout))
  139. #else
  140.         if((Current != Command) && (ifp->trfp == stdout))
  141. #endif
  142.             return; /* Nothing to trace */
  143.     }
  144.  
  145.     time(&timer);
  146.     cp = ctime(&timer);
  147.     cp[24] = '\0';
  148.  
  149.     switch(direction){
  150.     case IF_TRACE_IN:
  151.         if((ifp->trace & IF_TRACE_NOBC)
  152.          && (Tracef[type].addrtest != NULLFP)
  153.          && (*Tracef[type].addrtest)(ifp,bp) == 0)
  154.             return;        /* broadcasts are suppressed */
  155. #ifdef MONITOR
  156.         if ((ifp->trace & IF_TRACE_PLAIN) == IF_TRACE_PLAIN)
  157.             fprintf(ifp->trfp, "(%s) ", kissname(ifp, bp, type));
  158.         else
  159. #endif
  160.             fprintf(ifp->trfp,"\n%s - %s recv:\n",cp,ifp->name);
  161.         break;
  162.     case IF_TRACE_OUT:
  163. #ifdef MONITOR
  164.         if ((ifp->trace & IF_TRACE_PLAIN) == IF_TRACE_PLAIN)
  165.             fprintf(ifp->trfp, "(%s) ", kissname(ifp, bp, type));
  166.         else
  167. #endif
  168.             fprintf(ifp->trfp,"\n%s - %s sent:\n",cp,ifp->name);
  169.         break;
  170.     }
  171.     if(bp == NULLBUF || (size = len_p(bp)) == 0){
  172.         fprintf(ifp->trfp,"empty packet!!\n");
  173.         return;
  174.     }
  175.  
  176.     if(type < NCLASS)
  177.         func = Tracef[type].tracef;
  178.     else
  179.         func = NULLVFP;
  180.  
  181.     dup_p(&tbp,bp,0,size);
  182.     if(tbp == NULLBUF){
  183.         fprintf(ifp->trfp,nospace);
  184.         return;
  185.     }
  186. #ifdef MONITOR
  187.     Trace_compact_header = ((ifp->trace&IF_TRACE_PLAIN) == IF_TRACE_PLAIN);
  188. #endif
  189.     if(func != NULLVFP)
  190.         (*func)(ifp->trfp,&tbp,1);
  191. #ifdef MONITOR
  192.     if ((ifp->trace & IF_TRACE_PLAIN) == IF_TRACE_PLAIN)
  193.         plain_dump(ifp->trfp, &tbp);
  194.     else
  195. #endif
  196.     if(ifp->trace & IF_TRACE_ASCII){
  197.         /* Dump only data portion of packet in ascii */
  198.         ascii_dump(ifp->trfp,&tbp);
  199.     } else if(ifp->trace & IF_TRACE_HEX){
  200.         /* Dump entire packet in hex/ascii */
  201.         free_p(tbp);
  202.         dup_p(&tbp,bp,0,len_p(bp));
  203.         if(tbp != NULLBUF)
  204.             hex_dump(ifp->trfp,&tbp);
  205.         else
  206.             fprintf(ifp->trfp,nospace);
  207.     }
  208.     free_p(tbp);
  209. }
  210.  
  211. /* Dump packet bytes, no interpretation */
  212. void
  213. raw_dump(ifp,direction,bp)
  214. struct iface *ifp;
  215. int direction;
  216. struct mbuf *bp;
  217. {
  218.     struct mbuf *tbp;
  219.  
  220.     /* Dump entire packet in hex/ascii */
  221.     fprintf(ifp->trfp,"\n******* raw packet dump (%s %s)\n",
  222.         ((direction & IF_TRACE_OUT) ? "send" : "recv"),ifp->name);
  223.     dup_p(&tbp,bp,0,len_p(bp));
  224.     if(tbp != NULLBUF)
  225.         hex_dump(ifp->trfp,&tbp);
  226.     else
  227.         fprintf(ifp->trfp,nospace);
  228.     fprintf(ifp->trfp,"*******\n");
  229.     free_p(tbp);
  230.     return;
  231. }
  232.  
  233. /* Dump an mbuf in hex */
  234. static void
  235. hex_dump(fp,bpp)
  236. FILE *fp;
  237. register struct mbuf **bpp;
  238. {
  239.     int16 n;
  240.     int16 address;
  241.     char buf[16];
  242.  
  243.     if(bpp == NULLBUFP || *bpp == NULLBUF)
  244.         return;
  245.  
  246.     address = 0;
  247.     pullup(bpp, buf, 1);    /* remove first zero byte */
  248.     while((n = pullup(bpp,buf,sizeof(buf))) != 0){
  249.         fmtline(fp,address,buf,n);
  250.         address += n;
  251.     }
  252. }
  253. /* Dump an mbuf in ascii */
  254. static void
  255. ascii_dump(fp,bpp)
  256. FILE *fp;
  257. register struct mbuf **bpp;
  258. {
  259.     int c;
  260.     register int16 tot;
  261.  
  262.     if(bpp == NULLBUFP || *bpp == NULLBUF)
  263.         return;
  264.  
  265.     tot = 0;
  266.     while((c = PULLCHAR(bpp)) != -1){
  267.         if((tot % 64) == 0)
  268.             fprintf(fp,"%04x  ",tot);
  269. #ifdef TNOS_68K
  270.         fprintf (fp, "%c", isprint(uchar(c)) ? c : '.');
  271. #else
  272.         putc(isprint(uchar(c)) ? c : '.',fp);
  273. #endif
  274.         if((++tot % 64) == 0)
  275.             fprintf(fp,"\n");
  276.     }
  277.     if((tot % 64) != 0)
  278.         fprintf(fp,"\n");
  279. }
  280. /* Print a buffer up to 16 bytes long in formatted hex with ascii
  281.  * translation, e.g.,
  282.  * 0000: 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f  0123456789:;<=>?
  283.  */
  284. static void
  285. fmtline(fp,addr,buf,len)
  286. FILE *fp;
  287. int16 addr;
  288. char *buf;
  289. int16 len;
  290. {
  291.     char line[80];
  292.     register char *aptr,*cptr;
  293.     register char c;
  294.  
  295.     memset(line,' ',sizeof(line));
  296.     ctohex(line,(int16)hibyte(addr));
  297.     ctohex(line+2,(int16)lobyte(addr));
  298.     aptr = &line[6];
  299.     cptr = &line[55];
  300.     while(len-- != 0){
  301.         c = *buf++;
  302.         ctohex(aptr,(int16)uchar(c));
  303.         aptr += 3;
  304.         c &= 0x7f;
  305.         *cptr++ = isprint(uchar(c)) ? c : '.';
  306.     }
  307.     *cptr++ = '\n';
  308. #ifdef TNOS_68K
  309.     *cptr = 0;
  310.     fprintf (fp, line);
  311. #else
  312.     fwrite(line,1,(unsigned)(cptr-line),fp);
  313. #endif
  314. }
  315. /* Convert byte to two ascii-hex characters */
  316. static void
  317. ctohex(buf,c)
  318. register char *buf;
  319. register int16 c;
  320. {
  321.     static char hex[] = "0123456789abcdef";
  322.  
  323.     *buf++ = hex[hinibble(c)];
  324.     *buf = hex[lonibble(c)];
  325. }
  326.  
  327. #ifdef MONITOR
  328. /* Dump an mbuf in ascii with newlines but no others. */
  329. /* Actually, we do limited VT100 parsing, since that seems popular here */
  330. static void
  331. plain_dump(fp,bpp)
  332. FILE *fp;
  333. register struct mbuf **bpp;
  334. {
  335.     struct mbuf *tmp;
  336.     int c, esc, nl;
  337.  
  338.     if (bpp == NULLBUFP || *bpp == NULLBUF)
  339.         return;
  340.  
  341.     /* check for lots of non-ASCII, non-VT100 and ascii_dump instead? */
  342.     dup_p(&tmp, *bpp, 0, len_p(*bpp));
  343.     nl = 0;
  344.     while ((c = PULLCHAR(&tmp)) != -1)
  345.     {
  346.         /*
  347.          * Printable characters are okay, as are \n \t \r \b \f \a \E
  348.          * Nulls and other control characters are verboten, as are meta
  349.          * controls.  Meta-printables are accepted, since they may be
  350.          * intended as PC graphics (but don't expect them to dump right
  351.          * from here because I don't decode them.  Maybe someday).
  352.          */
  353.         if (c < 8 || (c > 13 && c < 26) || (c > 27 && c < 32) ||
  354.             (c > 126 && c < 174) || c > 223)
  355.             nl = 1;
  356.     }
  357.     if (nl)
  358.     {
  359.         ascii_dump(fp, bpp);
  360.         return;
  361.     }
  362.     esc = 0;
  363.     nl = 1;
  364.     while ((c = PULLCHAR(bpp)) != -1)
  365.     {
  366.       if (c == 0x1B)
  367.           esc = !esc;
  368.       else if (esc == 1 && c == '[')
  369.           esc = 2;
  370.       else if (esc == 1)
  371.           esc = 0;
  372.       else if (esc == 2 && c != ';' && !isdigit(c))
  373.       {
  374.           /* handle some common cases? */
  375.           esc = 0;
  376.       }
  377.       else if (esc == 0 && c == '\r')
  378.       {
  379.           fprintf(fp, "\n");
  380.           nl = 1;
  381.       }
  382.       /* safe programming: not everyone *always* agrees on isprint */
  383.       else if (esc == 0 && c != '\n' && (isprint(c) || c == '\t'))
  384.       {
  385.           fprintf(fp, "%c", c);
  386.           nl = 0;
  387.       }
  388.     }
  389.     if (!nl)
  390.       fprintf(fp, "\n");
  391. }
  392. #endif
  393.  
  394.  
  395. /* Modify or displace interface trace flags */
  396. int
  397. dotrace(argc,argv,p)
  398. int argc;
  399. char *argv[];
  400. void *p;
  401. {
  402.     struct iface *ifp;
  403.     struct tracecmd *tp;
  404.  
  405.     if(argc < 2){
  406.         for(ifp = Ifaces; ifp != NULLIF; ifp = ifp->next)
  407.             showtrace(ifp);
  408.         return 0;
  409.     }
  410.     if((ifp = if_lookup(argv[1])) == NULLIF){
  411.         tprintf(Badinterface,argv[1]);
  412.         return 1;
  413.     }
  414.     if(ifp->port){
  415.         tprintf("No trace on this interface - use master.\n");
  416.         return 1;
  417.     }
  418.     if(argc == 2){
  419.         showtrace(ifp);
  420.         return 0;
  421.     }
  422.     /* MODIFY THIS TO HANDLE MULTIPLE OPTIONS */
  423.     if(argc >= 3){
  424.         for(tp = Tracecmd;tp->name != NULLCHAR;tp++)
  425.             if(strncmp(tp->name,argv[2],strlen(argv[2])) == 0)
  426.                 break;
  427.         if(tp->name != NULLCHAR)
  428.             ifp->trace = (ifp->trace & ~tp->mask) | tp->val;
  429.         else
  430.             ifp->trace = htoi(argv[2]);
  431.     }
  432.     /* Always default to stdout unless trace file is given */
  433.     if(ifp->trfp != NULLFILE && ifp->trfp != stdout)
  434.         fclose(ifp->trfp);
  435.     ifp->trfp = stdout;
  436.     if(ifp->trfile != NULLCHAR)
  437.         free(ifp->trfile);
  438.     ifp->trfile = NULLCHAR;
  439.  
  440.     if(argc >= 4){
  441.         if((ifp->trfp = fopen(argv[3],APPEND_TEXT)) == NULLFILE){
  442.             tprintf("Can't write to %s\n",argv[3]);
  443.             ifp->trfp = stdout;
  444.         } else {
  445.             ifp->trfile = strdup(argv[3]);
  446.         }
  447.     }
  448.     showtrace(ifp);
  449.     return 0;
  450. }
  451. /* Display the trace flags for a particular interface */
  452. static void
  453. showtrace(ifp)
  454. register struct iface *ifp;
  455. {
  456.     if(ifp == NULLIF)
  457.         return;
  458.     tprintf("%s:",ifp->name);
  459.     if(ifp->port){
  460.         tprintf(" trace on master interface only.\n");
  461.         return;
  462.     }
  463.     if(ifp->trace & (IF_TRACE_IN | IF_TRACE_OUT | IF_TRACE_RAW)){
  464.         if(ifp->trace & IF_TRACE_IN)
  465.             tprintf(" input");
  466.         if(ifp->trace & IF_TRACE_OUT)
  467.             tprintf(" output");
  468.  
  469.         if(ifp->trace & IF_TRACE_NOBC)
  470.             tprintf(" - no broadcasts");
  471.  
  472. #ifdef MONITOR
  473.         if ((ifp->trace & IF_TRACE_PLAIN) == IF_TRACE_PLAIN)
  474.             tprintf(" (Monitoring)");
  475.         else
  476. #endif
  477.         if(ifp->trace & IF_TRACE_HEX)
  478.             tprintf(" (Hex/ASCII dump)");
  479.         else if(ifp->trace & IF_TRACE_ASCII)
  480.             tprintf(" (ASCII dump)");
  481.         else
  482.             tprintf(" (headers only)");
  483.  
  484.         if(ifp->trace & IF_TRACE_RAW)
  485.             tprintf(" Raw output");
  486.  
  487.         if(ifp->trfile != NULLCHAR)
  488.             tprintf(" trace file: %s",ifp->trfile);
  489.         tprintf("\n");
  490.     } else
  491.         tprintf(" tracing off\n");
  492. }
  493.  
  494. /* shut down all trace files */
  495. void
  496. shuttrace()
  497. {
  498.     struct iface *ifp;
  499.  
  500.     for(ifp = Ifaces; ifp != NULLIF; ifp = ifp->next){
  501.         if(ifp->trfp != NULLFILE && ifp->trfp != stdout)
  502.             fclose(ifp->trfp);
  503.         if(ifp->trfile != NULLCHAR)
  504.             free(ifp->trfile);
  505.         ifp->trfile = NULLCHAR;
  506.         ifp->trfp = NULLFILE;
  507.     }
  508. }
  509.  
  510. #ifdef PPP
  511. /* Log messages of the form
  512.  * Tue Jan 31 00:00:00 1987 44.64.0.7:1003 open FTP
  513.  */
  514. #if    defined(ANSIPROTO)
  515. void
  516. trace_log(struct iface *ifp,char *fmt, ...)
  517. {
  518.     va_list ap;
  519.     char *cp;
  520.     long t;
  521.  
  522.     if(ifp->trfp == NULLFILE)
  523.         return;
  524.  
  525.     time(&t);
  526.     cp = ctime(&t);
  527.     rip(cp);
  528.     fprintf(ifp->trfp,"%s",cp);
  529.  
  530.     fprintf(ifp->trfp," - ");
  531.     va_start(ap,fmt);
  532.     vfprintf(ifp->trfp,fmt,ap);
  533.     va_end(ap);
  534.     fprintf(ifp->trfp,"\n");
  535. }
  536. #else
  537. /*VARARGS2*/
  538. void
  539. trace_log(ifp,fmt,arg1,arg2,arg3,arg4,arg5)
  540. struct iface *ifp;
  541. char *fmt;
  542. int arg1,arg2,arg3,arg4,arg5;
  543. {
  544.     char *cp;
  545.     long t;
  546.  
  547.     if(ifp->trfp == NULLFILE)
  548.         return;
  549.  
  550.     time(&t);
  551.     cp = ctime(&t);
  552.     rip(cp);
  553.     fprintf(ifp->trfp,"%s",cp);
  554.  
  555.     fprintf(ifp->trfp," - ");
  556.     fprintf(ifp->trfp,fmt,arg1,arg2,arg3,arg4,arg5);
  557.     fprintf(ifp->trfp,"\n");
  558. }
  559. #endif
  560. #endif /* PPP */
  561.  
  562. #endif /*TRACE*/
  563.  
  564.